/*
 * Copyright (c) 2006 ESRI
 *
 * All rights reserved under the copyright laws of the United States
 * and applicable international laws, treaties, and conventions.
 * 
 * You may freely redistribute and use this sample code, with or 
 * without modification, provided you include the original copyright
 * notice and use restrictions.  
 * See use restrictions at /arcgis/java/samples/userestrictions.
 */
/**
 * ArcGIS Engine Developer Sample
 * Application Name: Points2Dto3D
 */
package routing;

import java.io.File;

import com.esri.arcgis.datasourcesfile.ShapefileWorkspaceFactory;
import com.esri.arcgis.geodatabase.FeatureClass;
import com.esri.arcgis.geodatabase.Field;
import com.esri.arcgis.geodatabase.Fields;
import com.esri.arcgis.geodatabase.GeometryDef;
import com.esri.arcgis.geodatabase.IFeature;
import com.esri.arcgis.geodatabase.IFeatureBuffer;
import com.esri.arcgis.geodatabase.IFeatureClass;
import com.esri.arcgis.geodatabase.IFeatureCursor;
import com.esri.arcgis.geodatabase.IField;
import com.esri.arcgis.geodatabase.Workspace;
import com.esri.arcgis.geodatabase.esriFeatureType;
import com.esri.arcgis.geodatabase.esriFieldType;
import com.esri.arcgis.geometry.Point;
import com.esri.arcgis.geometry.UnknownCoordinateSystem;
import com.esri.arcgis.geometry.esriGeometryType;
import com.esri.arcgis.system.AoInitialize;
import com.esri.arcgis.system.EngineInitializer;
import com.esri.arcgis.system.PropertySet;
import com.esri.arcgis.system.esriLicenseProductCode;

/**
 *  This sample will convert a point shapefile with a designated
 *  attribute containing Z (height) values to a 3D Shapefile.
 *  This sample aims to demonstrate how to read and set feature
 *  class attributes, how to set geometries to be Z aware, and how
 *  to create feature classes.  As input, it takes a shapefile with
 *  a Z attribute field, and as output it creates a 3D shapefile.
 */
public class Points2Dto3D {
	/**
	 * @param inShapePath - path to input shapefile
	 * @param inShapeName - name of input shapefile
	 * @param zFieldName - name of attribute containing z value
	 * @param outShapePath - path to output shapefile
	 * @param outShapeName - name of output shapefile
	 */
	private static void create3DShape(String inShapePath, String inShapeName, String zFieldName, String outShapePath, String outShapeName) {
		int zField;
		
		try{
			// open input and output feature classes
			ShapefileWorkspaceFactory shapefileWorkspaceFactory = new ShapefileWorkspaceFactory();
			Workspace workspace = (Workspace) shapefileWorkspaceFactory.openFromFile(inShapePath, 0);
			FeatureClass inFeatureClass = new FeatureClass(workspace.openFeatureClass(inShapeName));
			
			// open input and output feature classes
			UnknownCoordinateSystem spatialRef = new UnknownCoordinateSystem();
			IFeatureClass outFeatureClass = createFeatureClass(outShapePath, outShapeName, esriGeometryType.esriGeometryPoint, true, true, spatialRef, 1000);
			
			// copy the input fields to the output feature class w/o overwriting system fields
			IField field;
			for(int i = 0; i < inFeatureClass.getFields().getFieldCount() - 1; i++) {
				if(inFeatureClass.getFields().getField(i).isEditable() && inFeatureClass.getFields().getField(i).getType() != esriFieldType.esriFieldTypeGeometry) {
					field = inFeatureClass.getFields().getField(i);
					if(outFeatureClass.getFields().findField(field.getName()) == -1) {
						outFeatureClass.addField(field);
					}
				}
			}
			
			// get a cursor off the input feature class
			IFeatureCursor inCursor = inFeatureClass.search(null, false);
			
			// get a cursor off the output feature class
			IFeatureBuffer outFeature= outFeatureClass.createFeatureBuffer();
			IFeatureCursor outCursor = outFeatureClass.IFeatureClass_insert(true);
			
			// loop through all the input features, cloning the shape,
			// looking up and adding the z value from the input table
			// and adding the new feature to the output feature class
			IFeature inFeature = inCursor.nextFeature();
			
			// only support points
			if (!(inFeature.getShape() instanceof Point)) {
				System.out.println("This tool requires point features as the input");
				System.out.println("Exiting...");
				System.exit(0);
			}
			
			for (int featureCtr = 1; inFeature != null; inFeature = inCursor.nextFeature(), featureCtr++) {
				zField = inFeature.getFields().findField(zFieldName);
				if(zField < 0) {
					System.out.println("  Field: " + zFieldName + " was not found in the input feature class: ");
					continue;
				}
				double zValue = Double.parseDouble(inFeature.getValue(zField).toString());
				//
				// Get the input geometry and clone it and set ZAware on it.
				//
				Point featureShapeAsPoint = (Point) inFeature.getShape();
				Point outPoint = (Point) featureShapeAsPoint.esri_clone();
				outPoint.setZAware(true);
				outPoint.setZ(zValue);
				outFeature.setShapeByRef(outPoint);
				
				System.out.println("  Point feature #" + featureCtr + ": (" + outPoint.getX() + ", " + outPoint.getY() + ", " + outPoint.getZ() + ")");
				
				// Copy field values from input feature to output feature, except for the shape value
				for(int fieldCtr = 0; fieldCtr < inFeatureClass.getFields().getFieldCount() - 1; fieldCtr++){
					int outFeatureFieldIndex = outFeature.getFields().findField(inFeatureClass.getFields().getField(fieldCtr).getName());
					if (outFeatureFieldIndex >= 0){
						if(outFeature.getFields().getField(outFeatureFieldIndex).isEditable() && 
								outFeature.getFields().getField(outFeatureFieldIndex).getType() != esriFieldType.esriFieldTypeGeometry) {
							outFeature.setValue(outFeatureFieldIndex, inFeature.getValue(outFeatureFieldIndex));
						}
					}
				}
				outCursor.insertFeature(outFeature);
			}
			inCursor.flush();
		}
		catch(Exception e) {
			e.printStackTrace();
			System.exit(-1);
		}
	}
	
	private static IFeatureClass createFeatureClass(String outShapePath, String outShapeName, int shapeType, boolean hasM, boolean hasZ, UnknownCoordinateSystem spatialRef, int gridSize) {
		IFeatureClass outFeatureClass = null;
		try{
			PropertySet connectionProperties = new PropertySet();
			connectionProperties.setProperty("DATABASE", outShapePath);
			ShapefileWorkspaceFactory shapefileWorkspaceFactory = new ShapefileWorkspaceFactory();
			Workspace outFeatureWorkspace = (Workspace) shapefileWorkspaceFactory.open(connectionProperties, 0);
			
			Fields fields = new Fields();

			Field field = new Field();
			field.setName("OBJECTID");
			field.setAliasName("OBJECTID");
			field.setType(esriFieldType.esriFieldTypeOID);
			fields.addField(field);
			
			GeometryDef geometryDef = new GeometryDef();
			geometryDef.setGeometryType(shapeType);
			geometryDef.setHasM(hasM);
			geometryDef.setHasZ(hasZ);
			geometryDef.setSpatialReferenceByRef(spatialRef);
			geometryDef.setGridCount(1);
			geometryDef.setGridSize(0, gridSize);

			field = new Field();
			field.setName("SHAPE");
			field.setIsNullable(true);
			field.setType(esriFieldType.esriFieldTypeGeometry);
			field.setGeometryDefByRef(geometryDef);
			field.setRequired(true);
			fields.addField(field);
			
			outFeatureClass = outFeatureWorkspace.createFeatureClass(outShapeName, fields, null, null, esriFeatureType.esriFTSimple, "Shape", "");
		}
		catch(Exception e){
			e.printStackTrace();
			System.exit(-1);
		}
		return outFeatureClass;
	}
	
	/**
	 * Description:
	 * Main Method - Application Entry Point
	 * @param args String[]
	 */
	public static void main(String[] args) { 
		System.out.println("Starting Points2Dto3D - An ArcObjects Java SDK Developer Sample");
		String arcGISHome = System.getenv("ARCGISHOME");
		if (!(new File(arcGISHome).exists())) {
			System.out.println(arcGISHome + " does not exist.\nExiting...");
			System.exit(-1);
		}
		//
		// Change the following lines if you want to use different data
		//
		String inShapePath = arcGISHome + "/java/samples/data/usa";
		String inShapeName = "wind.shp";
		String outShapePath = arcGISHome + "/java/samples/output_data/points2dto3d";
		String outShapeName = "3dshape.shp";
		String zFieldName = "VELOCITY";

		File outShapefileDir = new File(outShapePath);
		outShapefileDir.mkdir();

		File outShapefileFile = new File(outShapefileDir, outShapeName);
		if (outShapefileFile.exists()) {
			System.out.println("Output shapefile already exists: " + outShapefileFile.getAbsolutePath());
			System.out.println("Delete it (plus related files) and rerun");
			System.exit(0);
		}
		
		EngineInitializer.initializeEngine();
		try {
			AoInitialize aoInitializer = new AoInitialize();
			aoInitializer.initialize( esriLicenseProductCode.esriLicenseProductCodeEngine );
			Points2Dto3D.create3DShape(inShapePath, inShapeName, zFieldName, outShapePath, outShapeName);
			System.out.println("Output shapefile created: " + outShapefileFile.getAbsolutePath());
			aoInitializer.shutdown();
			System.out.println("Done");
		} catch ( Exception e ) {
			System.out.println("Error: " + e.getMessage());
			System.exit(-1);
		}
	}
}
